# -*- coding: utf-8 -*-

# 炮手游戏

import sys, time, random, math, pygame
from pygame.locals import *
from MyLibrary import *
from datetime import datetime, date, time

reload(sys)
sys.setdefaultencoding('utf-8')

screen_width = 800
screen_height = 600


def angular_velocity(angle):
    vel = Point(0, 0)
    vel.x = math.cos(math.radians(angle))
    vel.y = math.sin(math.radians(angle))
    return vel


class Terrain():
    def __init__(self, min_height, max_height, total_points):
        self.min_height = min_height
        self.max_height = max_height
        self.total_points = total_points+1
        self.grid_size = screen_width/total_points
        self.height_map = list()
        self.generate()

    def generate(self):
        # clear list
        if len(self.height_map) > 0:
            for n in range(self.total_points):
                self.height_map.pop()

        # first point
        last_height = (self.max_height + self.min_height) / 2
        self.height_map.append(last_height)
        direction = 1
        run_length = 0

        # 后续点
        for n in range(1, self.total_points):
            rand_dist = random.randint(1, 5)*direction
            height = last_height + rand_dist
            self.height_map.append(int(height))

            # 这里会导致地图尖锐的凸起
            if height < self.min_height:
                direction = 1
            elif height > self.max_height:
                direction = -1

            last_height = height
            if run_length <= 0:
                run_length = random.randint(1, 6)
                direction = random.randint(1, 2)
                if direction == 2: direction = -1
            else:
                run_length -= 1

    def draw(self, surface):
        global grid_point
        last_x = 0
        for n in range(1, self.total_points):
            height = screen_height - self.height_map[n]
            x_pos = int(n * self.grid_size)
            pos = (x_pos, height)
            color = (255, 255, 255)
            # pygame.draw.circle(surface, color, pos, 4, 1)
            if n == grid_point:
                pygame.draw.circle(surface, (0,255,0), pos, 4, 0)

            last_height = screen_height - self.height_map[n-1]
            last_pos = (last_x, last_height)
            pygame.draw.line(surface, color, last_pos, pos, 2)
            last_x = x_pos

    def get_height(self, x):
        x_point = int(x/self.grid_size)
        return self.height_map[x_point]


def game_init():
    global screen, font, timer, backbuffer, player_group, \
    enemy_tank, bullets, crosshair, crosshair_group, terrain

    pygame.init()
    winstyle = 0  # |FULLSCREEN
    bestdepth = pygame.display.mode_ok((screen_width, screen_height), winstyle, 32)
    screen = pygame.display.set_mode((screen_width, screen_height), winstyle, bestdepth)

    pygame.display.set_caption("炮手游戏")
    font = pygame.font.Font("mini.ttf", 20)
    # pygame.mouse.set_visible(False)
    timer = pygame.time.Clock()

    # 背面缓存技术
    backbuffer = pygame.Surface((screen_width, screen_height))

    terrain = Terrain(50, 400, 100)


def draw_player_cannon(surface, position):
    # 炮台
    turret_color = (30, 180, 30)
    start_x = position.x + 15
    start_y = position.y + 15
    start_pos = (start_x, start_y)
    vel = angular_velocity(wrap_angle(player_cannon_angle-90))
    end_pos = (start_x + vel.x*30, start_y+vel.y*30)
    pygame.draw.line(surface, turret_color, start_pos, end_pos, 6)

    # 炮身体
    body_color = (30, 200, 30)
    rect = Rect(position.x, position.y+15, 30, 15)
    pygame.draw.rect(surface, body_color, rect, 0)
    pygame.draw.circle(surface, body_color, (position.x+15,position.y+15),15,0)

    # angle = wrap_angle(player_cannon_angle-90)
    # player_shell_velocity = angular_velocity(angle)
    # player_shell_velocity.x *= player_cannon_angle
    # player_shell_velocity.y *= player_cannon_angle
    # player_shell_position = player_cannon_position
    # player_shell_position.x += 15
    # player_shell_position.y += 15
    #
    # if player_firing:
    #     player_shell_position.x += player_shell_velocity.x
    #     player_shell_position.y += player_shell_velocity.y


def draw_computer_cannon(surface, position):
    # 炮台
    turret_color = (220, 180, 30)
    start_x = position.x + 15
    start_y = position.y + 15
    start_pos = (start_x, start_y)
    vel = angular_velocity(wrap_angle(computer_cannon_angle - 90))
    end_pos = (start_x + vel.x * 30, start_y + vel.y * 30)
    pygame.draw.line(surface, turret_color, start_pos, end_pos, 6)

    # 炮身体
    body_color = (220, 30, 30)
    rect = Rect(position.x, position.y + 15, 30, 15)
    pygame.draw.rect(surface, body_color, rect, 0)
    pygame.draw.circle(surface, body_color, (position.x + 15, position.y + 15), 15, 0)


game_init()
game_over = False
player_score = 0
enemy_score = 0
last_time = 0
mouse_x = mouse_y = 0
grid_point = 0
player_score = computer_score = 0
player_cannon_position = Point(0, 0)
player_cannon_angle = 45
player_cannon_power = 8.0
computer_cannon_position = Point(0, 0)
computer_cannon_angle = 315
computer_cannon_power = 8.0

player_firing = False
player_shell_position = Point(0, 0)
player_shell_velocity = Point(0, 0)

computer_firing = False
computer_shell_position = Point(0, 0)
computer_shell_velocity = Point(0, 0)

while True:
    # global terrain
    timer.tick(30)
    ticks = pygame.time.get_ticks()

    # reset
    mouse_up = mouse_down = 0
    mouse_up_x = mouse_up_y = 0
    mouse_down_x = mouse_down_y = 0

    for event in pygame.event.get():
        if event.type == QUIT: sys.exit()
        elif event.type == MOUSEMOTION:
            mouse_x, mouse_y = event.pos
            move_x, move_y = event.rel

        elif event.type == MOUSEBUTTONUP:
            terrain.generate()

    keys = pygame.key.get_pressed()
    if keys[K_ESCAPE]: sys.exit()
    elif keys[K_LEFT] or keys[K_a]:
        if player_cannon_power > 0.0: player_cannon_power -= 0.1
    elif keys[K_RIGHT] or keys[K_d]:
        if player_cannon_power <= 10.0: player_cannon_power += 0.1
    elif keys[K_UP] or keys[K_w]:
        player_cannon_angle = wrap_angle(player_cannon_angle-1)
    elif keys[K_DOWN] or keys[K_s]:
        player_cannon_angle = wrap_angle(player_cannon_angle + 1)

    if keys[K_SPACE]:
        if not player_firing:
            player_firing = True
            angle = wrap_angle(player_cannon_angle-90)
            player_shell_velocity = angular_velocity(angle)
            player_shell_velocity.x *= player_cannon_power
            player_shell_velocity.y *= player_cannon_power
            player_shell_position = player_cannon_position
            player_shell_position.x += 15
            player_shell_position.y += 15

    if not game_over:
        # 让炮台角度合理,不朝地下
        if player_cannon_angle > 180:
            if player_cannon_angle < 270: player_cannon_angle = 270
        elif player_cannon_angle <= 180:
            if player_cannon_angle > 90: player_cannon_angle = 90

        # 计算鼠标角度
        grid_point = int(mouse_x / terrain.grid_size)
        # 移动玩家炮弹
        if player_firing:
            player_shell_position.x += player_shell_velocity.x
            player_shell_position.y += player_shell_velocity.y

            # 炮弹击中地形
            height = screen_height - terrain.get_height(player_shell_position.x)
            if player_shell_position.y > height:
                player_firing = False   # 击中

            if player_shell_velocity.y < 10.0:
                player_shell_velocity.y += 0.1  # 模拟重力, 上升越来越慢

            # 炮弹飞出屏幕
            if player_shell_position.x < 0 or player_shell_position.x > screen_width:
                player_firing = False
            if player_shell_position.y < 0 or player_shell_position.y > screen_height:
                player_firing = False

        # 移动电脑炮弹
        if computer_firing:
            computer_shell_position.x += computer_shell_velocity.x
            computer_shell_position.y += computer_shell_velocity.y

            # 炮弹击中地形
            height = screen_height - terrain.get_height(computer_shell_position.x)
            if computer_shell_position.y > height:
                computer_firing = False  # 击中

            if computer_shell_velocity.y < 10.0:
                computer_shell_velocity.y += 0.1  # 模拟重力, 上升越来越慢

            # 炮弹飞出屏幕
            if computer_shell_position.x < 0 or computer_shell_position.x > screen_width:
                computer_firing = False
            if computer_shell_position.y < 0 or computer_shell_position.y > screen_height:
                computer_firing = False
        else:
            # 电脑发射炮弹
            computer_firing = True
            computer_cannon_power = random.randint(1, 10)

            angle = wrap_angle(computer_cannon_angle - 90)
            computer_shell_velocity = angular_velocity(angle)
            computer_shell_velocity.x *= computer_cannon_power
            computer_shell_velocity.y *= computer_cannon_power
            computer_shell_position = computer_cannon_position
            computer_shell_position.x += 15
            computer_shell_position.y += 15

        # 玩家炮弹击中电脑
        if player_firing:
            dist = distance(player_shell_position, computer_cannon_position)
            if dist < 30:
                player_score += 1
                player_firing = False

        # 电脑炮弹击中玩家
        if computer_firing:
            dist = distance(computer_shell_position, player_cannon_position)
            if dist < 30:
                computer_score += 1
                computer_firing = False

    # 画屏幕
    backbuffer.fill((20, 20, 120))

    # 地形
    terrain.draw(backbuffer)

    # 玩家
    y = screen_height - terrain.get_height(70+15) - 20
    player_cannon_position = Point(70, y)
    draw_player_cannon(backbuffer, player_cannon_position)

    # 电脑
    y = screen_height - terrain.get_height(700 + 15) - 20
    computer_cannon_position = Point(700, y)
    draw_computer_cannon(backbuffer, computer_cannon_position)

    # 玩家炮弹
    if player_firing:
        x = int(player_shell_position.x)
        y = int(player_shell_position.y)
        pygame.draw.circle(backbuffer, (20, 230, 20), (x, y), 4, 0)

    # 电脑炮弹
    if computer_firing:
        x = int(computer_shell_position.x)
        y = int(computer_shell_position.y)
        pygame.draw.circle(backbuffer, (230, 20, 20), (x, y), 4, 0)

    # 绘制备份缓存
    screen.blit(backbuffer, (0, 0))

    if not game_over:
        print_text(font, 0, 0, u"SCORE " + str(player_score))
        print_text(font, 0, 20, u"ANGLE " + "{:.1f}".format(player_cannon_angle))
        print_text(font, 0, 40, u"POWER " + "{:.2f}".format(player_cannon_power))
        if player_firing:
            print_text(font, 0, 60, u"FIRING")

        print_text(font, 650, 0, u"SCORE " + str(computer_score))
        print_text(font, 650, 20, u"ANGLE " + "{:.1f}".format(computer_cannon_angle))
        print_text(font, 650, 40, u"POWER " + "{:.2f}".format(computer_cannon_power))
        if computer_firing:
            print_text(font, 650, 60, u"FIRING")

        print_text(font, 0, 580, u"CURSOR " + str(Point(mouse_x, mouse_y)) + \
                   ", GRID POINT " + str(grid_point) + ", HEIGHT " + \
                   str(terrain.get_height(mouse_x)))
    else:
        print_text(font, 0, 0, u"GAME OVER")

    pygame.display.update()


pygame.quit()



